﻿namespace Text2Rss.Web.Controllers
{
	#region Using Directives
	using System;
	using System.Collections.Generic;
	using System.Linq;
	using System.Web;
	using System.Web.Mvc;
	using System.Web.Routing;
	using System.Web.Security;
	using NHibernate;
	using Text2Rss.Web.DtoModels;
	using Text2Rss.Web.Models;
	using Text2Rss.Web.Services;
	#endregion

	/// <summary>
	/// Registering and logging on
	/// </summary>
	public class AccountController : BaseController
	{
		#region Constructor
		/// <summary>
		/// Initializes a new instance of the AccountController class
		/// </summary>
		/// <param name="sessionFactory"></param>
		public AccountController(ISessionFactory sessionFactory)
			: base(sessionFactory)
		{

		}
		#endregion

		#region LogOn/LogOff
		/// <summary>
		/// Returnes Log On view
		/// </summary>
		/// <returns>LogOn view</returns>
		public ActionResult LogOn()
		{
			return View();
		}

		/// <summary>
		/// Performs Log on action
		/// </summary>
		/// <param name="model">LogOn model</param>
		/// <param name="returnUrl">Return Url</param>
		/// <returns>Appropriate view</returns>
		[HttpPost]
		public ActionResult LogOn(LogOnModel model, string returnUrl)
		{
			if (ModelState.IsValid)
			{
				User user = LoadUser(model);
				if (user != null)
				{
					FormsAuthentication.SetAuthCookie(model.Email, model.RememberMe);
					if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/")
						&& !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\"))
					{
						return Redirect(returnUrl);
					}
					else
					{
						return RedirectToAction("Index", "Home");
					}
				}
				else
				{
					ModelState.AddModelError(string.Empty, "The user name or password provided is incorrect.");
				}
			}

			// If we got this far, something failed, redisplay form
			return View(model);
		}

		private User LoadUser(LogOnModel model)
		{
			User user = null;
			using (var session = SessionFactory.OpenSession())
			{
				SecurityService service = new SecurityService(session);
				user = service.ValidateUser(model.Email, model.Password);
			}
			return user;
		}

		/// <summary>
		/// Performs Log off action
		/// </summary>
		/// <returns>Redirec to Home</returns>
		public ActionResult LogOff()
		{
			FormsAuthentication.SignOut();

			return RedirectToAction("Index", "Home");
		}
		#endregion

		#region Register
		/// <summary>
		/// Shows Register view
		/// </summary>
		/// <returns>View for registering</returns>
		public ActionResult Register()
		{
			return View();
		}

		/// <summary>
		/// Registers the user
		/// </summary>
		/// <param name="model">User's model</param>
		/// <returns></returns>
		[HttpPost]
		public ActionResult Register(RegisterModel model)
		{
			if (ModelState.IsValid)
			{
				// Attempt to register the user
				MembershipCreateStatus createStatus;
				Membership.CreateUser(model.UserName, model.Password, model.Email, null, null, true, null, out createStatus);

				if (createStatus == MembershipCreateStatus.Success)
				{
					FormsAuthentication.SetAuthCookie(model.UserName, false /* createPersistentCookie */);
					return RedirectToAction("Index", "Home");
				}
				else
				{
					ModelState.AddModelError(string.Empty, ErrorCodeToString(createStatus));
				}
			}

			// If we got this far, something failed, redisplay form
			return View(model);
		}
		#endregion

		#region ChangePassword
		/// <summary>
		/// Shows Change password View
		/// </summary>
		/// <returns></returns>
		[Authorize]
		public ActionResult ChangePassword()
		{
			return View();
		}

		/// <summary>
		/// Changes Password
		/// </summary>
		/// <param name="model">Model for password changing</param>
		/// <returns>View according to result of the operation</returns>
		[Authorize]
		[HttpPost]
		public ActionResult ChangePassword(ChangePasswordModel model)
		{
			if (ModelState.IsValid)
			{
				// ChangePassword will throw an exception rather
				// than return false in certain failure scenarios.
				bool changePasswordSucceeded;
				try
				{
					MembershipUser currentUser = Membership.GetUser(User.Identity.Name, true /* userIsOnline */);
					changePasswordSucceeded = currentUser.ChangePassword(model.OldPassword, model.NewPassword);
				}
				catch (Exception)
				{
					changePasswordSucceeded = false;
				}

				if (changePasswordSucceeded)
				{
					return RedirectToAction("ChangePasswordSuccess");
				}
				else
				{
					ModelState.AddModelError(string.Empty, "The current password is incorrect or the new password is invalid.");
				}
			}

			// If we got this far, something failed, redisplay form
			return View(model);
		}

		/// <summary>
		/// Shows success view
		/// </summary>
		/// <returns></returns>
		public ActionResult ChangePasswordSuccess()
		{
			return View();
		}
		#endregion

		#region Status Codes
		/// <summary>
		/// Returs localized error code string
		/// </summary>
		/// <param name="createStatus">Error status</param>
		/// <returns>Lolized error code string</returns>
		private static string ErrorCodeToString(MembershipCreateStatus createStatus)
		{
			// See http://go.microsoft.com/fwlink/?LinkID=177550 for
			// a full list of status codes.
			switch (createStatus)
			{
				case MembershipCreateStatus.DuplicateUserName:
					return "User name already exists. Please enter a different user name.";

				case MembershipCreateStatus.DuplicateEmail:
					return "A user name for that e-mail address already exists. Please enter a different e-mail address.";

				case MembershipCreateStatus.InvalidPassword:
					return "The password provided is invalid. Please enter a valid password value.";

				case MembershipCreateStatus.InvalidEmail:
					return "The e-mail address provided is invalid. Please check the value and try again.";

				case MembershipCreateStatus.InvalidAnswer:
					return "The password retrieval answer provided is invalid. Please check the value and try again.";

				case MembershipCreateStatus.InvalidQuestion:
					return "The password retrieval question provided is invalid. Please check the value and try again.";

				case MembershipCreateStatus.InvalidUserName:
					return "The user name provided is invalid. Please check the value and try again.";

				case MembershipCreateStatus.ProviderError:
					return "The authentication provider returned an error. Please verify your entry and try again. If the problem persists, please contact your system administrator.";

				case MembershipCreateStatus.UserRejected:
					return "The user creation request has been canceled. Please verify your entry and try again. If the problem persists, please contact your system administrator.";

				default:
					return "An unknown error occurred. Please verify your entry and try again. If the problem persists, please contact your system administrator.";
			}
		}
		#endregion
	}
}
